home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue25 / system / MATCH.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-08-08  |  5.3 KB  |  222 lines

  1. unit Match;
  2. {
  3.   File: match.pas
  4.   Author: Kevin Boylan
  5.  
  6.   This code is meant to allow wildcard pattern matches.  It is VERY useful for matching filename wildcard
  7.   patterns.  It allows unix grep-like pattern comparisons, for instance:
  8.  
  9.     ?    Matches any single characer
  10.     *    Matches any contiguous characters
  11.     [abc]    Matches a or b or c at that position
  12.     [^abc]    Matches anything but a or b or c at that position
  13.     [!abc]    Ditto
  14.     [a-e]    Matches a through e at that position
  15.  
  16.     'ma?ch.*'    -Would match match.exe, mavch.dat, march.on, etc
  17.     'this [e-n]s a [!zy]est' -Would match 'this is a test', but would not match 'this as a yest'
  18.  
  19.   This is a Delphi VCL translation from C code that was downloaded from CIS.  That C code was written
  20.   by J. Kerceval and released to public domain 02/20/1991.  This code is ofcourse also public domain.
  21.   I would appreciate it if you would let me know if you find any bugs.  I would also appreciate any
  22.   notes sent my way letting me know if you find it useful.  My email address is
  23.   Internet:    75221.1057@compuserve.com
  24.  
  25.   Some tidying up by Dave Jewell.
  26. }
  27.  
  28. interface
  29.  
  30. function IsMatch (const pattern, text: String): Boolean;
  31.  
  32. implementation
  33.  
  34. uses SysUtils;
  35.  
  36. const
  37.     { match defines }
  38.     MATCH_PATTERN        = 6;
  39.     MATCH_LITERAL        = 5;
  40.     MATCH_RANGE            = 4;
  41.     MATCH_ABORT            = 3;
  42.     MATCH_END            = 2;
  43.     MATCH_VALID            = 1;
  44.  
  45. function matche( pattern, text: String ): Integer; forward;
  46. function match_after_star( pattern, text: String ): Integer; forward;
  47.  
  48. function IsMatch (const pattern, text: String ): Boolean;
  49. begin
  50.     Result := matche( pattern, text ) = 1;
  51. end;
  52.  
  53. function matche (pattern, text: String): Integer;
  54. var
  55.     invert, member_match, loop: Boolean;
  56.     range_start, range_end, p, t, plen, tlen: Integer;
  57. begin
  58.     p := 1; t := 1;
  59.     pattern := LowerCase (pattern);
  60.     text := LowerCase (Text);
  61.     plen := Length (pattern) ;
  62.     tlen := Length (text);
  63.     Result := 0;
  64.  
  65.     while (Result = 0) and (p <= plen) do
  66.     begin
  67.         if t > tlen then
  68.         begin
  69.             if (pattern [p] = '*') and (p + 1 > plen) then
  70.                 Result := MATCH_VALID
  71.             else
  72.                 Result := MATCH_ABORT;
  73.             Exit;
  74.         end
  75.     else case pattern[p] of
  76.           '*':
  77.         Result := match_after_star (Copy (pattern, p, plen), Copy (text,t,tlen));
  78.          '[':
  79.             begin
  80.             Inc (p);
  81.             invert := False;
  82.             if pattern [p] in ['!', '^'] then
  83.             begin
  84.                 invert := True;
  85.             Inc (p);
  86.                 end;
  87.  
  88.         if pattern[p] = ']' then
  89.         begin
  90.             Result := MATCH_PATTERN;
  91.             Exit;
  92.         end;
  93.  
  94.         member_match := False;
  95.         loop := True;
  96.         while loop and (pattern[p] <> ']') do
  97.                 begin
  98.             range_start := p;
  99.             range_end := p;
  100.             Inc (p);
  101.             if p > plen then
  102.             begin
  103.                 Result := MATCH_PATTERN;
  104.             Exit;
  105.                  end;
  106.  
  107.             if pattern[p] = '-' then
  108.                     begin
  109.                 Inc(p);
  110.                 range_end := p;
  111.                 if (p > plen) or (pattern[range_end] = ']') then
  112.                 begin
  113.                     Result := MATCH_PATTERN;
  114.                 Exit;
  115.                         end;
  116.             Inc(p);
  117.                     end;
  118.  
  119.             if p > plen then
  120.             begin
  121.                 Result := MATCH_PATTERN;
  122.                 Exit;
  123.                end;
  124.  
  125.             if range_start < range_end then
  126.               begin
  127.                 if (text[t] >= pattern[range_start]) and
  128.                (text[t] <= pattern[range_end]) then
  129.             begin
  130.                 member_match := True;
  131.                 loop := False;
  132.             end;
  133.             end
  134.             else
  135.                     begin
  136.                   if (text[t] >= pattern[range_end]) and
  137.                   (text[t] <= pattern[range_start]) then
  138.                 begin
  139.                 member_match := True;
  140.                 loop := False;
  141.             end;
  142.                     end;
  143.                 end;
  144.  
  145.             if (invert and member_match) or (not(invert or member_match)) then
  146.                 begin
  147.             Result := MATCH_RANGE;
  148.             Exit;
  149.         end;
  150.  
  151.         if member_match then while (p <= plen) and (pattern[p] <> ']') do Inc(p);
  152.         if p > plen then begin
  153.                Result := MATCH_PATTERN;
  154.             Exit;
  155.         end;
  156.             end; { MATCH_CHAR_RANGE_OPEN: }
  157.  
  158.         else if pattern[p] <> '?' then
  159.             if (pattern[p] <> text[t]) then
  160.             Result := MATCH_LITERAL;
  161.         end; { Case pattern[p] }
  162.  
  163.     Inc(p);
  164.     Inc(t);
  165.     end;
  166.  
  167.     if Result = 0 then
  168.     if (t <= tlen) then
  169.            Result := MATCH_END
  170.         else
  171.         Result := MATCH_VALID;
  172. end;
  173.  
  174. function match_after_star( pattern, text: String ): Integer;
  175. var
  176.     p, t, plen, tlen: Integer;
  177. begin
  178.     Result := 0;
  179.     p := 1; t := 1;
  180.     plen := Length (pattern);
  181.     tlen := Length(text);
  182.     while ((t <= tlen) and (p < plen)) and
  183.     (pattern[p] = '?') or
  184.     (pattern[p] = '*') do
  185.     begin
  186.         if pattern [p] = '?' then Inc(t);
  187.     Inc(p);
  188.     end;
  189.  
  190.     if t > tlen then begin
  191.     Result := MATCH_ABORT;
  192.     Exit;
  193.     end;
  194.  
  195.     if p > plen then begin
  196.         Result := MATCH_VALID;
  197.     Exit;
  198.     end;
  199.  
  200.     repeat
  201.         if (pattern[p] = text[t]) or (pattern[p] = '[') then
  202.     begin
  203.             pattern := Copy (pattern, p, plen);
  204.         text := Copy (text,t,tlen);
  205.         plen := Length (pattern);
  206.         tlen := Length (text);
  207.         p := 1; t := 1;
  208.           Result := matche( pattern , text );
  209.         end;
  210.  
  211.         if t > tlen then begin
  212.           Result := MATCH_ABORT;
  213.         Exit;
  214.         end;
  215.  
  216.     Inc(t);
  217.     until (Result = 1) or (t > tlen);
  218. end;
  219.  
  220. end.
  221.  
  222.